<!DOCTYPE html>
<html lang="zh-Hant">
<head>
    <meta charset="UTF-8">
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0">
    <title>我的電視·〇</title>
    <style>
        body {
            height: 100vh;
            margin: 0;
            padding: 1rem;
            background-color: #263238;
            color: #EEEEEE;
        }

        a {
            color: #EEEEEE;
        }

        hr {
            margin-top: .5rem;
            margin-bottom: .5rem;
        }

        label {
            display: inline-block;
            width: 100%;
            margin-bottom: .5rem;
        }

        textarea {
            resize: none;
            overflow: auto;
        }

        input[type="file"] {
            color: #EEEEEE;
            cursor: pointer;
        }

        input, textarea {
            color: #1a1a1a;
            padding: .6rem;
            border: none;
            border-radius: 4px;
            transition: box-shadow 0.3s ease-in-out;
            vertical-align: bottom;
        }

        input:focus, textarea:focus {
            outline: none;
            border-color: #66afe9;
            box-shadow: 0 0 10px rgba(102, 175, 233, 0.6);
        }

        .container {
            display: flex;
            flex-direction: row;
        }

        input[type="text"], input[type="number"], textarea {
            flex: 1;
            box-sizing: border-box;
        }

        input[type="text"], input[type="number"], input[type="file"], input[type="button"] {
            height: 2.6rem;
        }

        input[type="button"] {
            margin-left: .6rem;
            cursor: pointer;
        }

        .source-grey {
            background-color: grey;
        }

        .source-green {
            background-color: darkslategray;
        }

        .history {
            margin-top: 10px;
        }

        .history > input[type="text"], .history > input[type="number"] {
            color: #EEEEEE;
        }

        .message-box {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 10px 20px;
            background-color: #333;
            color: #fff;
            border-radius: 5px;
            opacity: 0;
            transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
            transform: translateX(100%);
        }

        .message-box.show {
            opacity: 1;
            transform: translateX(0);
        }
    </style>
</head>
<body>
<h1 class="title">我的電視·〇</h1>
<h4>視頻源可以设置為地址/文本/文件其中之一</h4>
<h4>視頻源文本轉換：<a target="_blank" href="https://lizongying.github.io/js-gua64/">六十四卦編碼</a></h4>
<hr/>

<div class="item">
    <label for="uri" id="uri-label">視頻源地址</label>
    <div class="container">
        <input type="text" id="uri"/>
        <input type="button" id="confirm-uri" value="新增" class="add"/>
    </div>
    <div id="sources-new"></div>
    <div id="source"></div>
</div>

<hr/>

<div class="item">
    <label for="plain-text" id="plain-text-label">視頻源文本</label>
    <div class="container">
        <textarea id="plain-text" rows="4"/></textarea>
        <input type="button" id="confirm-plain-text" value="確認" class="confirm"/>
    </div>
</div>

<hr/>

<div class="item">
    <label for="upload-file" id="upload-file-label">視頻源文件，選擇後會自動上傳保存</label>
    <div class="container">
        <input type="file" id="upload-file" multiple/>
    </div>
</div>

<hr/>

<div class="item">
    <label for="channel" id="channel-label">默認播放頻道號，從1開始。0代表默認設置</label>
    <div class="container">
        <input type="number" id="channel" min="0" max="99"/>
        <input type="button" id="confirm-channel" value="確認" class="confirm"/>
    </div>
</div>

<hr/>

<div class="item">
    <label for="epg" id="epg-label">EPG</label>
    <div class="container">
        <input type="text" id="epg"/>
        <input type="button" id="confirm-epg" value="確認" class="confirm"/>
    </div>
</div>

<hr/>

<div class="item">
    <label for="proxy" id="proxy-label">代理地址</label>
    <div class="container">
        <input type="text" id="proxy"/>
        <input type="button" id="confirm-proxy" value="確認" placeholder="http://0.0.0.0:0" class="confirm"/>
    </div>
</div>

<hr/>

<div id="messageBox" class="message-box"></div>

<div style="height: 100%"></div>
</body>
<script>
    const lang = {
        TRADITIONAL_CHINESE: {
            appName: '我的電視·〇',
            description: '視頻源可以设置為地址/文本/文件其中之一',
            uriLabel: '視頻源地址',
            plainTextLabel: '視頻源文本',
            uploadFileLabel: '視頻源文件，選擇後會自動上傳保存',
            channelLabel: '默認播放頻道，從1開始。0代表默认設置',
            epgLabel: 'EPG',
            proxyLabel: '代理地址',
            confirm: '確認',
            remove: '刪除',
            add: '新增',
        },
        SIMPLIFIED_CHINESE: {
            appName: '我的电视·〇',
            description: '视频源可以设置为地址/文本/文件其中之一',
            uriLabel: '视频源地址',
            plainTextLabel: '视频源文本',
            uploadFileLabel: '视频源文件，选择后会自动上传保存',
            channelLabel: '默认播放频道，从1开始。0代表默認设置',
            epgLabel: 'EPG',
            proxyLabel: '代理地址',
            confirm: '确认',
            remove: '删除',
            add: '新增',
        }
    };
    const t = (key) => lang['TRADITIONAL_CHINESE'][key];
    document.querySelector('h1').innerText = t('appName');
    document.querySelector('h4').innerText = t('description');
    document.querySelector('#uri-label').innerText = t('uriLabel');
    document.querySelector('#plain-text-label').innerText = t('plainTextLabel');
    document.querySelector('#upload-file-label').innerText = t('uploadFileLabel');
    document.querySelector('#channel-label').innerText = t('channelLabel');
    document.querySelector('#epg-label').innerText = t('epgLabel');
    document.querySelector('#proxy-label').innerText = t('proxyLabel');
    document.querySelectorAll('.confirm').forEach(
        i => i.value = t('confirm')
    );
    document.querySelectorAll('.add').forEach(
        i => i.value = t('add')
    );

    const source = document.querySelector('#source');

    const uploadFile = document.querySelector('#upload-file');

    uploadFile.onchange = function (e) {
        handleFiles(e.target.files)
    }

    const handleFiles = async function (files) {
        for (let i = 0; i < files.length; i++) {
            await read(files[i]);
        }
    }

    const read = async (file) => {
        const reader = new FileReader();
        reader.onload = (e) => {
            save('/api/import-text', e.target.result);
        };
        reader.readAsText(file);
    }

    ['#uri', '#plain-text', '#channel', '#epg', '#proxy'].forEach(e => {
        const ele = document.querySelector(e);
        ele.addEventListener('focus', () => {
            ele.scrollIntoView({
                behavior: 'smooth',
                block: 'start'
            });
        });
    })

    document.querySelector('#confirm-uri').onclick = () => {
        let uri = document.querySelector('#uri').value.trim();
        if (!uri) {
            alert(`無效的地址${uri}`);
            return;
        }
        if (!uri.startsWith('http')) {
            uri = 'http://' + uri;
        }
        if (!uri.startsWith('http')) {
            alert(`無效的地址${uri}`);
            return;
        }
        if (!isValidUrl(uri)) {
            alert(`無效的地址${uri}`);
            return;
        }
        document.querySelector('#uri').value = uri;

        if (uri.length > 0) {
            const uuid = uuidV4()
            save('/api/import-uri', JSON.stringify({
                id: uuid,
                uri: uri,
            }))
            showMessage('已確認', 3000);

            let htmlString = `<div class="container history"><input type="text" readonly value="${uri}" class="source-grey"/><input type="button" value="删除" class="remove" data-source-id="${uuid}"/></div>`;
            let doc = new DOMParser().parseFromString(htmlString, 'text/html');
            const firstChild = source.firstChild;
            if (firstChild) {
                source.insertBefore(doc.body.firstChild, firstChild);
            } else {
                source.appendChild(doc.body.firstChild);
            }

            handleRemove()
        }
    }

    document.querySelector('#confirm-plain-text').onclick = () => {
        const content = document.querySelector('#plain-text').value.trim();
        if (content.length > 0) {
            save('/api/import-text', content)
            showMessage('已確認', 3000);
        } else {
            alert(`內容為空`);
        }
    }

    document.querySelector('#confirm-channel').onclick = () => {
        const channel = document.querySelector('#channel').value.trim();
        if (channel.length > 0) {
            save('/api/default-channel', JSON.stringify({
                channel: channel
            }))
            showMessage('已確認', 3000);
        } else {
            alert(`內容為空`);
        }
    }

    document.querySelector('#confirm-epg').onclick = () => {
        const epg = document.querySelector('#epg').value.trim();
        save('/api/epg', JSON.stringify({
            epg: epg
        }))

        showMessage('已確認', 3000);
    }

    document.querySelector('#confirm-proxy').onclick = () => {
        let proxy = document.querySelector('#proxy').value.trim();
        if (proxy && (!proxy.startsWith('http') && !proxy.startsWith('socks'))) {
            proxy = 'http://' + proxy;
        }
        if (proxy && (!proxy.startsWith('http') && !proxy.startsWith('socks'))) {
            alert(`無效的地址${proxy}`);
            return;
        }
        if (proxy && !isValidUrl(proxy)) {
            alert(`無效的地址${proxy}`);
            return;
        }
        document.querySelector('#proxy').value = proxy;
        save('/api/proxy', JSON.stringify({
            proxy: proxy
        }))

        showMessage('已確認', 3000);
    }

    const save = async (url, body) => {
        const response = await fetch(url, {
            method: 'POST',
            body: body
        });
        const json = await response.text();
        console.log(json);
    }

    const handleRemove = () => {
        const removes = document.querySelectorAll('.remove');
        [...removes].forEach(remove => {
            remove.value = t('remove');
            remove.onclick = () => {
                const sourceId = remove.dataset.sourceId.trim();
                console.log('sourceId', sourceId);
                save('/api/remove-source', JSON.stringify({
                    sourceId: sourceId
                }))
                remove.parentElement.remove()
            }
        })
    }

    const handleAdd = () => {
        const addList = document.querySelectorAll('.new-source');
        [...addList].forEach(add => {
            add.value = t('add');
            add.onclick = () => {
                const uri = add.dataset.uri.trim();
                console.log('uri', uri);

                const uuid = uuidV4();
                save('/api/import-uri', JSON.stringify({
                    id: uuid,
                    uri: uri,
                }));

                add.parentElement.remove();

                let htmlString = `<div class="container history"><input type="text" readonly value="${uri}" class="source-grey"/><input type="button" value="删除" class="remove" data-source-id="${uuid}"/></div>`;
                let doc = new DOMParser().parseFromString(htmlString, 'text/html');
                const firstChild = source.firstChild;
                if (firstChild) {
                    source.insertBefore(doc.body.firstChild, firstChild);
                } else {
                    source.appendChild(doc.body.firstChild);
                }

                handleRemove();

                document.querySelector('#uri').value = uri;
            }
        })
    }

    const uuidV4 = () => {
        return ([1e7] + '-' + 1e3 + '-' + 4e3 + '-' + 8e3 + '-' + 1e11).replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        );
    }

    const isValidUrl = (url) => {
        try {
            new URL(url);
            return true;
        } catch (e) {
            return false;
        }
    }

    (async () => {
        const response = await fetch('/api/settings');
        const json = await response.json();
        console.log(json);
        document.querySelector('#channel').value = json.channelDefault;
        document.querySelector('#uri').value = json.channelUri;
        document.querySelector('#plain-text').value = json.channelText;
        document.querySelector('#epg').value = json.epg;
        document.querySelector('#proxy').value = json.proxy;

        json.history.forEach(v => {
            let htmlString = `<div class="container history"><input type="text" readonly value="${v.uri}" class="source-grey"/><input type="button" value="删除" class="remove" data-source-id="${v.id}"/></div>`;
            let doc = new DOMParser().parseFromString(htmlString, 'text/html');
            source.appendChild(doc.body.firstChild);
        })

        handleRemove()

        const sources = await fetch('/api/sources');
        const sourcesText = await sources.text();
        console.log(sourcesText);

        const histories = json.history.map(v => v.uri)

        const sourcesNew = document.querySelector('#sources-new');
        sourcesText.trim().split("\n").forEach(v => {
            if (histories.includes(v)) {
                return
            }

            let htmlString = `<div class="container history"><input type="text" readonly value="${v}" class="source-green"/><input type="button" value="新增" class="add new-source" data-uri="${v}"/></div>`;
            let doc = new DOMParser().parseFromString(htmlString, 'text/html');
            sourcesNew.appendChild(doc.body.firstChild);
        })

        handleAdd()
    })()

    const showMessage = (message, duration = 3000) => {
        const messageBox = document.getElementById('messageBox');
        messageBox.textContent = message;
        messageBox.classList.add('show');

        setTimeout(() => {
            messageBox.classList.remove('show');
        }, duration);
    }
</script>
</html>
